package com.hmall.item.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.api.dto.OrderDetailDTO;
import com.hmall.common.domain.PageDTO;
import com.hmall.common.exception.BizIllegalException;
import com.hmall.common.utils.BeanUtils;
import com.hmall.item.domain.dto.ItemDTO;
import com.hmall.item.domain.po.Item;
import com.hmall.item.domain.query.ItemPageQuery;
import com.hmall.item.mapper.ItemMapper;
import com.hmall.item.service.IItemService;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * <p>
 * 商品表 服务实现类
 * </p>
 *
 * @author itheima
 */
@Service
public class ItemServiceImpl extends ServiceImpl<ItemMapper, Item> implements IItemService {
    @Autowired
    private RestHighLevelClient client;

    /**
     *  是给下单后 需要扣减库存调用
     * @param items
     */
    @Override
    public void deductStock(List<OrderDetailDTO> items) {
        String sqlStatement = "com.hmall.item.mapper.ItemMapper.updateStock";
        boolean r = false;
        try {
            r = executeBatch(items, (sqlSession, entity) -> sqlSession.update(sqlStatement, entity));
        } catch (Exception e) {
            log.error("更新库存异常", e);
          //  return;
            throw new BizIllegalException("库存不足!");
        }
        if (!r) {
            throw new BizIllegalException("库存不足！");
        }
    }

    @Override
    public List<ItemDTO> queryItemByIds(Collection<Long> ids) {
        return BeanUtils.copyList(listByIds(ids), ItemDTO.class);
    }

    @Override
    public PageDTO<ItemDTO> search(ItemPageQuery query) {
        try {
            //1.创建搜索对象
            SearchRequest searchRequest = new SearchRequest("items");
            //2.封装搜索条件
            //bool 包裹所有查询
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            //2.1搜索框 如果有数据，进行模糊搜索，没有match——all
            if (StrUtil.isNotBlank(query.getKey())) {
                boolQueryBuilder.must(QueryBuilders.matchQuery("name", query.getKey()));
            } else {
                boolQueryBuilder.must(QueryBuilders.matchAllQuery());
            }
            //2.2  分类,品牌，价格
            if (StrUtil.isNotBlank(query.getCategory())) {
                boolQueryBuilder.filter(QueryBuilders.termQuery("category", query.getCategory()));
            }
            if (StrUtil.isNotBlank(query.getBrand())){
                boolQueryBuilder.filter(QueryBuilders.termQuery("brand", query.getBrand()));
            }
            if (query.getMinPrice() != null ||  query.getMaxPrice() != null){
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").from(query.getMinPrice()).to(query.getMaxPrice()));
            }

            //3.指定分页参数
            searchRequest.source()
                    .from((query.getPageNo() - 1) * query.getPageSize())
                            .size(query.getPageSize());
            //4.指定排序方式和字段
            if(StrUtil.isNotBlank(query.getSortBy())){
                searchRequest.source().sort(query.getSortBy(),query.getIsAsc() ? SortOrder.ASC : SortOrder.DESC);
            }
            //5.高亮设置
            searchRequest.source().highlighter(
                    SearchSourceBuilder.highlight()
                            .field("name")
                            .requireFieldMatch(false)
            );
            //6.发送请求，执行搜索
            searchRequest.source().query(boolQueryBuilder);
            SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
            //7.解析结果：封装dto/解析高亮
            long total = response.getHits().getTotalHits().value;
            ArrayList<ItemDTO> list = new ArrayList<>();
            SearchHit[] hits = response.getHits().getHits();
            for (SearchHit hit : hits) {
                ItemDTO itemDTO = JSONUtil.toBean(hit.getSourceAsString(), ItemDTO.class);
                //解析高亮
                if(hit.getHighlightFields().containsKey("name")){
                    itemDTO.setName(hit.getHighlightFields().get("name").getFragments()[0].toString());
                }
                //添加到集合
                list .add(itemDTO);
            }

            //计算总页数
            long pages = total % query.getPageSize() == 0 ? total / query.getPageSize() : total / query.getPageSize() + 1;


            //8.返回结果
            return new PageDTO<>(total,  pages, list);

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
